package com.yc.cinema.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
@Aspect
public class MyAspect {

    // Aspectj表达式 execution
    // 前置增强
    @Before("execution(* com.yc.cinema.biz.UserBiz.*(..))")
    public void before(JoinPoint joinPoint){
        System.out.println("===========before===========");
        // 方法签名
        System.out.println(joinPoint.getSignature());
        // 参数列表
        System.out.println(Arrays.toString(joinPoint.getArgs()));
    }

    // 接口注入
    // 后置增强
    @After("execution(* com.yc.cinema.biz.UserBiz.*(..))")
    public void after(JoinPoint joinPoint){
        System.out.println("===========after===========");
    }

    // 切点方法
    @Pointcut("execution(* com.yc.cinema.biz.UserBiz.*(..))")
    public void pointcut(){

    }

    // 异常增强 ： 业务出现异常时的增强
    // throwing 异常参数名 =》注入
    @AfterThrowing(value = "pointcut()", throwing = "throwable")
    public void throwing(JoinPoint joinPoint, Throwable throwable){
        System.out.println("===========throwing===========" + throwable);
    }

    // 返回增强 : 当业务方法正常返回结果时的增强
    @AfterReturning(pointcut = "pointcut()", returning = "ret")
    public void returning(JoinPoint joinPoint, Object ret){
        System.out.println("===========returning===========" + ret);
    }

    // 环绕增强  TODO
    // 方法的返回值 =》 业务方法的返回值
    // 业务方法的执行， 由环绕增强连接点对象执行
    @Around("execution(* com.yc..aop.*.*(..))")
    public Object around(ProceedingJoinPoint pjp){
        System.out.println("===========around============");

        long time =  System.currentTimeMillis();
        try {
            // 执行业务方法
            Object ret = pjp.proceed();
            time = System.currentTimeMillis() - time;
            System.out.print(pjp.getSignature());
            System.out.printf(" 执行了 %d 毫秒" , time);
            return ret;
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            return null;
        }
    }





}
